<script lang="ts">
  import {
    create_node,
    remove_node,
    update_node_lock,
    update_node_position,
    update_node_size,
    type ExDrawNodeInfo,
  } from "$lib/api/board/board_draw";
  import { get_user_session } from "$lib/api/user";
  import { request } from "$lib/utils/request";
  import {
    Handle,
    Position,
    NodeResizer,
    type NodeProps,
    type ResizeParams,
  } from "@xyflow/svelte";
  import type { Snippet } from "svelte";
  import { drawStore } from "../../store.svelte";
  import {
    Copy,
    Trash2,
    Lock,
    LockOpen,
    PenLine,
    PaintRoller,
  } from "lucide-svelte";
  import { unSelectNode } from "../../DrawFlowHelp.svelte";
  import EditStyleModal from "../../modal/edit/EditStyleModal.svelte";
  import EditContentModal from "../../modal/edit/EditContentModal.svelte";
  import EditMermaidNodeModal from "../../modal/develop/EditMermaidNodeModal.svelte";
  import EditLinkNodeModal from "../../modal/EditLinkNodeModal.svelte";

  interface NodeWrapProps {
    nodeProps: NodeProps;
    children: Snippet<[]>;
    showBorder: boolean;
    showBgColor: boolean;
    showResizer: boolean;
    keepAspectRatio?: boolean;
    hideHandle?: boolean;
    onSizeChange?: () => void;
  }

  const props: NodeWrapProps = $props();

  const nodeInfo = $derived(props.nodeProps.data as ExDrawNodeInfo);
  const hover = $derived(drawStore.hoverNodeId == props.nodeProps.id);

  const llmNode = $derived(
    nodeInfo.content.LlmAskContent != undefined ||
      nodeInfo.content.LlmAnswerContent != undefined,
  );

  const noConnLllNode = $derived(
    nodeInfo.content.LlmAnswerContent != undefined,
  );

  const canEditContent = $derived(
    nodeInfo.content.BasicEllipseContent != undefined ||
      nodeInfo.content.BasicRectangleContent != undefined ||
      nodeInfo.content.TextContent != undefined ||
      nodeInfo.content.BasicLinkContent != undefined ||
      nodeInfo.content.DevelopMermaidContent != undefined,
  );

  const releateNode = $derived(() => {
    const releateEdges = drawStore.edgeList.filter(
      (item) =>
        drawStore.selectNodeIdList.includes(item.edge_key.from_node_id) ||
        drawStore.selectNodeIdList.includes(item.edge_key.to_node_id) ||
        drawStore.hoverNodeId == item.edge_key.from_node_id ||
        drawStore.hoverNodeId == item.edge_key.to_node_id,
    );
    const tmpNodeIdList = [
      ...releateEdges.map((item) => item.edge_key.from_node_id),
      ...releateEdges.map((item) => item.edge_key.to_node_id),
    ];
    return (
      tmpNodeIdList.includes(nodeInfo.node_id) ||
      nodeInfo.node_id == drawStore.hoverNodeId
    );
  });

  let showEditContentModal = $state(false);
  let showEditStyleModal = $state(false);

  async function changeSize(params: ResizeParams) {
    const tmpList = drawStore.nodeList.slice();
    try {
      const sessionId = await get_user_session();
      await request(
        update_node_size({
          session_id: sessionId,
          board_id: drawStore.boardInfo?.board_id ?? "",
          draw_id: drawStore.drawId,
          node_id: nodeInfo.node_id,
          w: params.width,
          h: params.height,
        }),
      );
      let x = params.x;
      let y = params.y;
      await request(
        update_node_position({
          session_id: sessionId,
          board_id: drawStore.boardInfo?.board_id ?? "",
          draw_id: drawStore.drawId,
          node_id: nodeInfo.node_id,
          x: x,
          y: y,
        }),
      );
      if (props.onSizeChange != undefined) {
        props.onSizeChange();
      }
    } catch (e) {
      drawStore.nodeList = tmpList;
    }
  }

  async function removeNode() {
    if (nodeInfo.lock) {
      return;
    }
    const sessionId = await get_user_session();
    await request(
      remove_node({
        session_id: sessionId,
        board_id: drawStore.boardInfo?.board_id ?? "",
        draw_id: drawStore.drawId,
        node_id: props.nodeProps.id,
      }),
    );
    drawStore.removeSelectNodeId(props.nodeProps.id);
  }

  async function dupNode() {
    const sessionId = await get_user_session();
    await request(
      create_node({
        session_id: sessionId,
        board_id: drawStore.boardInfo?.board_id ?? "",
        draw_id: drawStore.drawId,
        x: nodeInfo.x + 80,
        y: nodeInfo.y + 80,
        w: nodeInfo.w,
        h: nodeInfo.h,
        content: nodeInfo.content,
        node_style: nodeInfo.node_style,
      }),
    );
  }

  async function updateNodeLock() {
    const sessionId = await get_user_session();
    const curLock = nodeInfo.lock;
    await request(
      update_node_lock({
        session_id: sessionId,
        board_id: drawStore.boardInfo?.board_id ?? "",
        draw_id: drawStore.drawId,
        node_id: nodeInfo.node_id,
        lock: !curLock,
      }),
    );
    unSelectNode(nodeInfo.node_id);
  }

  $effect(() => {
    if (props.nodeProps.selected) {
      setTimeout(() => {
        drawStore.addSelectNodeId(props.nodeProps.id);
      }, 100);
    } else {
      drawStore.removeSelectNodeId(props.nodeProps.id);
    }
  });
</script>

<div
  role="none"
  class={`relative w-full h-full ${props.showBorder ? nodeInfo.node_style.border_width : ""} ${props.showBorder ? nodeInfo.node_style.border_color : ""} ${props.showBgColor ? nodeInfo.node_style.bg_color : ""} ${nodeInfo.node_style.font_color} ${releateNode() ? "" : "opacity-75"}`}
  onmouseenter={() => (drawStore.hoverNodeId = nodeInfo.node_id)}
  onmouseleave={() => {
    setTimeout(() => {
      if (drawStore.hoverNodeId == nodeInfo.node_id) {
        drawStore.hoverNodeId = "";
      }
    }, 200);
  }}
>
  <div class="absolute left-[10px] top-[4px] flex gap-2">
    {#if drawStore.readOnly == false && hover && llmNode == false}
      <button
        type="button"
        class="btn text-primary-800-200 bg-surface-300-700 p-1 hover:text-primary-900-100 z-50"
        onclick={() => updateNodeLock()}
      >
        {#if nodeInfo.lock}
          <Lock size={14} />
        {:else}
          <LockOpen size={14} />
        {/if}
      </button>
    {/if}
  </div>
  <div class="absolute right-[10px] bottom-[4px] flex gap-2">
    {#if drawStore.readOnly == false && hover && (nodeInfo.content.TextContent != undefined || nodeInfo.content.BasicSvgContent != undefined || nodeInfo.content.BasicEllipseContent != undefined || nodeInfo.content.BasicRectangleContent != undefined)}
      <button
        type="button"
        title="复制当前节点"
        class="btn text-primary-800-200 bg-surface-300-700 p-1 hover:text-primary-900-100 z-50"
        onclick={() => dupNode()}
      >
        <Copy size={14} />
      </button>
    {/if}
    {#if drawStore.readOnly == false && hover && drawStore.inConnect == false && nodeInfo.lock == false}
      <button
        type="button"
        title="删除"
        class="btn text-error-600-400 bg-error-100-900 p-1 hover:bg-error-200-800 hover:text-error-900-100 z-50"
        onclick={() => removeNode()}
      >
        <Trash2 size={14} />
      </button>
    {/if}
  </div>

  <div class="absolute right-[10px] top-[4px] flex gap-2">
    {#if drawStore.readOnly == false && hover && !llmNode && canEditContent && nodeInfo.lock == false}
      <button
        type="button"
        title="编辑内容"
        class="btn text-primary-800-200 bg-surface-300-700 p-1 hover:text-primary-900-100 z-50"
        onclick={() => (showEditContentModal = true)}
      >
        <PenLine size={14} />
      </button>
    {/if}
    {#if drawStore.readOnly == false && hover && !llmNode && nodeInfo.lock == false}
      <button
        type="button"
        title="编辑样式"
        class="btn text-primary-800-200 bg-surface-300-700 p-1 hover:text-primary-900-100 z-50"
        onclick={() => (showEditStyleModal = true)}
      >
        <PaintRoller size={14} />
      </button>
    {/if}
  </div>
  <NodeResizer
    minWidth={100}
    minHeight={100}
    keepAspectRatio={props.keepAspectRatio}
    isVisible={props.nodeProps.selected && props.showResizer}
    color="var(--color-primary-300)"
    lineStyle="border-width: 2px;"
    handleStyle="width:10px; height:10px; border-radius:10px;"
    shouldResize={() => !drawStore.readOnly}
    onResizeEnd={(_e, params) => {
      changeSize(params);
    }}
  />
  {#if props.hideHandle != true}
    <Handle
      id="l"
      type="source"
      position={Position.Left}
      style={`background:var(--color-surface-500);width:10px;height:10px; ${(!drawStore.readOnly && hover && !llmNode) || (drawStore.inConnect && !noConnLllNode) ? "opacity:1.0" : "opacity:0"};`}
      isConnectable
    />
    <Handle
      id="r"
      type="source"
      position={Position.Right}
      style={`background:var(--color-surface-500);width:10px;height:10px; ${(!drawStore.readOnly && hover && !llmNode) || (drawStore.inConnect && !noConnLllNode) ? "opacity:1.0" : "opacity:0"};`}
      isConnectable
    />
    <Handle
      id="t"
      type="source"
      position={Position.Top}
      style={`background:var(--color-surface-500);width:10px;height:10px; ${(!drawStore.readOnly && hover && !llmNode) || (drawStore.inConnect && !noConnLllNode) ? "opacity:1.0" : "opacity:0"};`}
      isConnectable
    />
    <Handle
      id="b"
      type="source"
      position={Position.Bottom}
      style={`background:var(--color-surface-500);width:10px;height:10px; ${(!drawStore.readOnly && hover && !llmNode) || (drawStore.inConnect && !noConnLllNode) ? "opacity:1.0" : "opacity:0"};`}
      isConnectable
    />
  {/if}
  {@render props.children()}
</div>

<div class="absolute -left-[10000px]">
  {#if showEditStyleModal}
    <EditStyleModal
      node={nodeInfo}
      onClose={() => (showEditStyleModal = false)}
    />
  {/if}
  {#if showEditContentModal}
    {#if nodeInfo.content.BasicLinkContent != undefined}
      <EditLinkNodeModal
        nodeId={nodeInfo.node_id}
        content={nodeInfo.content.BasicLinkContent}
        onClose={() => (showEditContentModal = false)}
      />
    {:else if nodeInfo.content.DevelopMermaidContent != undefined}
      <EditMermaidNodeModal
        {nodeInfo}
        onClose={() => (showEditContentModal = false)}
      />
    {:else if nodeInfo.content.TextContent != undefined || nodeInfo.content.BasicEllipseContent != undefined || nodeInfo.content.BasicRectangleContent != undefined}
      <EditContentModal
        node={nodeInfo}
        onClose={() => (showEditContentModal = false)}
      />
    {/if}
  {/if}
</div>
